{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 决策树算法\n",
    "## 关键问题：\n",
    "1. 如何训练模型？\n",
    "2. 如何验证精度？\n",
    "3. 如何调整超参数优化模型？\n",
    "4. 如何可视化？\n",
    "5. 如何处理布尔型变量？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import load_iris\n",
    "from sklearn.tree import DecisionTreeClassifier,export_graphviz\n",
    "import graphviz\n",
    "from sklearn.model_selection import train_test_split,GridSearchCV\n",
    "import pandas as pd\n",
    "from sklearn import  metrics\n",
    "from collections import Counter\n",
    "from imblearn.over_sampling import RandomOverSampler\n",
    "from imblearn.under_sampling import RandomUnderSampler\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 鸢尾花数据集\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)\n",
      "0                  5.1               3.5                1.4               0.2\n",
      "1                  4.9               3.0                1.4               0.2\n",
      "2                  4.7               3.2                1.3               0.2\n",
      "3                  4.6               3.1                1.5               0.2\n",
      "4                  5.0               3.6                1.4               0.2\n",
      "..                 ...               ...                ...               ...\n",
      "145                6.7               3.0                5.2               2.3\n",
      "146                6.3               2.5                5.0               1.9\n",
      "147                6.5               3.0                5.2               2.0\n",
      "148                6.2               3.4                5.4               2.3\n",
      "149                5.9               3.0                5.1               1.8\n",
      "\n",
      "[150 rows x 4 columns]\n",
      "0      0\n",
      "1      0\n",
      "2      0\n",
      "3      0\n",
      "4      0\n",
      "      ..\n",
      "145    2\n",
      "146    2\n",
      "147    2\n",
      "148    2\n",
      "149    2\n",
      "Name: target, Length: 150, dtype: int32\n"
     ]
    }
   ],
   "source": [
    "iris_x,iris_y = load_iris(as_frame=True,return_X_y=True)\n",
    "print(iris_x)\n",
    "print(iris_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "target\n",
      "0    50\n",
      "1    50\n",
      "2    50\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# 查看各类别是否分布均匀\n",
    "iris_y_count=iris_y.value_counts()\n",
    "print(iris_y_count)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({2: 35, 0: 35, 1: 35}) Counter({2: 15, 0: 15, 1: 15})\n"
     ]
    }
   ],
   "source": [
    "# 划分训练集和测试集\n",
    "x_train,x_test,y_train,y_test = train_test_split(iris_x,iris_y,test_size=0.3,random_state=0,stratify=iris_y)\n",
    "print(Counter(y_train),Counter(y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {color: black;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>DecisionTreeClassifier(criterion=&#x27;entropy&#x27;)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">DecisionTreeClassifier</label><div class=\"sk-toggleable__content\"><pre>DecisionTreeClassifier(criterion=&#x27;entropy&#x27;)</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "DecisionTreeClassifier(criterion='entropy')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 训练决策树模型\n",
    "clf=DecisionTreeClassifier(criterion='entropy')\n",
    "clf.fit(x_train,y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy 0.9111111111111111\n",
      "混淆矩阵\n",
      " [[15  0  0]\n",
      " [ 0 13  2]\n",
      " [ 0  2 13]]\n",
      "f1core 0.9111111111111111\n"
     ]
    }
   ],
   "source": [
    "# 训练决策树模型\n",
    "clf=DecisionTreeClassifier(criterion='entropy')\n",
    "clf.fit(x_train,y_train)\n",
    "#进行预测并计算准确率\n",
    "y_pred=clf.predict(x_test)\n",
    "accuracy=metrics.accuracy_score(y_test,y_pred)\n",
    "confusion_matrix=metrics.confusion_matrix(y_test,y_pred)\n",
    "f1score=metrics.f1_score(y_test,y_pred,average='weighted')\n",
    "print('accuracy',accuracy)\n",
    "print('混淆矩阵\\n',confusion_matrix)\n",
    "print('f1core',f1score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'决策树可视化.pdf'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dot_data = export_graphviz(clf, out_file=None,feature_names=['sepal length','sepal width','petal length','petal width'],\n",
    "                           filled=True,rounded=True,class_names=['0','1','2']) \n",
    "graph = graphviz.Source(dot_data) \n",
    "graph.render('决策树可视化')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用实验四数据构建决策树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      ID        Wet        Dry   Ele  Slope  Aspect  Class\n",
      "0      1  26.873888  24.097786  1767     15      28      1\n",
      "1      2  24.905001  21.823750  1802     13      91      1\n",
      "2      3  24.373030  20.003288  1820      0       0      1\n",
      "3      4  23.386429  18.135881  1829      4     276      1\n",
      "4      5  21.663076  17.128407  1837      9     257      1\n",
      "..   ...        ...        ...   ...    ...     ...    ...\n",
      "595  596  11.860588  12.959253  4802      0       0      0\n",
      "596  597  11.624545  12.031395  4807      4     179      0\n",
      "597  598   9.338000  10.029155  4828      0       0      0\n",
      "598  599  10.443334  10.579853  4841      0       0      0\n",
      "599  600  10.321579  11.768931  4845      2     188      0\n",
      "\n",
      "[600 rows x 7 columns]\n",
      "Counter({0: 510, 1: 90})\n"
     ]
    }
   ],
   "source": [
    "original_data=pd.read_csv(\"D:\\Lenovo\\Desktop\\云南大学\\空间数据挖掘\\实验数据\\实验数据4.csv\")\n",
    "print(original_data)\n",
    "print(Counter(original_data['Class']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用欠采样平衡类别占比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({0: 408, 1: 72}) Counter({0: 102, 1: 18})\n",
      "Counter({0: 72, 1: 72}) Counter({0: 18, 1: 18})\n"
     ]
    }
   ],
   "source": [
    "X_train, X_test, Y_train, Y_test = train_test_split(original_data.drop(['Class','ID'], axis=1), \n",
    "                                                    original_data['Class'], test_size=0.2, random_state=0\n",
    "                                                    ,stratify=original_data['Class'])\n",
    "print(Counter(Y_train),Counter(Y_test))\n",
    "#两种类别不平衡，使用欠采样平衡类别占比\n",
    "undersampler=RandomUnderSampler(random_state=0)\n",
    "X_train_resampled, Y_train_resampled =undersampler.fit_resample(X_train, Y_train)\n",
    "X_test_resampled, Y_test_resampled = undersampler.fit_resample(X_test, Y_test)\n",
    "print(Counter(Y_train_resampled),Counter(Y_test_resampled))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-2 {color: black;}#sk-container-id-2 pre{padding: 0;}#sk-container-id-2 div.sk-toggleable {background-color: white;}#sk-container-id-2 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-2 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-2 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-2 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-2 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-2 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-2 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-2 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-2 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-2 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-2 div.sk-item {position: relative;z-index: 1;}#sk-container-id-2 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-2 div.sk-item::before, #sk-container-id-2 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-2 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-2 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-2 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-2 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-2 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-2 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-2 div.sk-label-container {text-align: center;}#sk-container-id-2 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-2 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>DecisionTreeClassifier(criterion=&#x27;entropy&#x27;, random_state=0)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" checked><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">DecisionTreeClassifier</label><div class=\"sk-toggleable__content\"><pre>DecisionTreeClassifier(criterion=&#x27;entropy&#x27;, random_state=0)</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "DecisionTreeClassifier(criterion='entropy', random_state=0)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#训练决策树模型\n",
    "clf2=DecisionTreeClassifier(criterion='entropy',random_state=0)\n",
    "clf2.fit(X_train_resampled,Y_train_resampled)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集准确率： 1.0\n",
      "决策树模型准确率： 0.8055555555555556\n",
      "混淆矩阵\n",
      " [[14  4]\n",
      " [ 3 15]]\n",
      "F1-score: 0.8108108108108109\n"
     ]
    }
   ],
   "source": [
    "y_pred2=clf2.predict(X_test_resampled)\n",
    "accuracy2=metrics.accuracy_score(Y_test_resampled,y_pred2)\n",
    "confusion_matrix2=metrics.confusion_matrix(Y_test_resampled,y_pred2)\n",
    "f1score2=metrics.f1_score(Y_test_resampled,y_pred2)\n",
    "accuracy_train=metrics.accuracy_score(Y_train_resampled,clf2.predict(X_train_resampled))\n",
    "print('训练集准确率：',accuracy_train)\n",
    "print(\"决策树模型准确率：\",accuracy2)\n",
    "print('混淆矩阵\\n',confusion_matrix2)\n",
    "print('F1-score:',f1score2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'实验四数据集决策树.pdf'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dot_data = export_graphviz(clf2, out_file=None,feature_names=['Wet','Dry','Ele','Slope','Aspect'],filled=True) \n",
    "graph = graphviz.Source(dot_data)\n",
    "graph.render('实验四数据集决策树')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用过采样平衡类别占比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({0: 408, 1: 408}) Counter({0: 102, 1: 102})\n",
      "训练集准确率： 1.0\n",
      "决策树模型准确率： 0.803921568627451\n",
      "混淆矩阵\n",
      " [[98  4]\n",
      " [36 66]]\n",
      "F1-score: 0.7674418604651163\n"
     ]
    }
   ],
   "source": [
    "oversampler=RandomOverSampler(random_state=0)\n",
    "X_train_resampled2, Y_train_resampled2 =oversampler.fit_resample(X_train, Y_train)\n",
    "X_test_resampled2, Y_test_resampled2 = oversampler.fit_resample(X_test, Y_test)\n",
    "print(Counter(Y_train_resampled2),Counter(Y_test_resampled2))\n",
    "#训练决策树模型\n",
    "clf2=DecisionTreeClassifier(criterion='entropy',random_state=0)\n",
    "clf2.fit(X_train_resampled2,Y_train_resampled2)\n",
    "y_pred2=clf2.predict(X_test_resampled2)\n",
    "accuracy2=metrics.accuracy_score(Y_test_resampled2,y_pred2)\n",
    "confusion_matrix2=metrics.confusion_matrix(Y_test_resampled2,y_pred2)\n",
    "f1score2=metrics.f1_score(Y_test_resampled2,y_pred2)\n",
    "accuracy_train=metrics.accuracy_score(Y_train_resampled2,clf2.predict(X_train_resampled2))\n",
    "print('训练集准确率：',accuracy_train)\n",
    "print(\"决策树模型准确率：\",accuracy2)\n",
    "print('混淆矩阵\\n',confusion_matrix2)\n",
    "print('F1-score:',f1score2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "欠采样效果更好   \n",
    "## 使用网格搜索法找到最优超参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最优参数: {'criterion': 'entropy', 'max_depth': 4, 'min_samples_leaf': 2, 'min_samples_split': 6}\n",
      "训练集准确率: 0.8916666666666667\n",
      "测试集准确率: 0.8333333333333334\n"
     ]
    }
   ],
   "source": [
    "#使用欠采样的数据集\n",
    "param_grid={'max_depth':np.arange(3,10,1),'min_samples_split':np.arange(2,10,1),\n",
    "            'criterion':['gini','entropy'],'min_samples_leaf':np.arange(1,10,1)}\n",
    "clf3=DecisionTreeClassifier(random_state=0)\n",
    "grid_search=GridSearchCV(clf3,param_grid,cv=3,n_jobs=-1)\n",
    "grid_search.fit(X_train_resampled,Y_train_resampled)\n",
    "print(\"最优参数:\",grid_search.best_params_)\n",
    "\n",
    "#使用最优参数重新训练模型\n",
    "best_tree=grid_search.best_estimator_\n",
    "model=best_tree.fit(X_train_resampled,Y_train_resampled)\n",
    "Y_train_pred=model.predict(X_train)\n",
    "Y_test_pred=model.predict(X_test)\n",
    "train_accuracy=metrics.accuracy_score(Y_train,Y_train_pred)\n",
    "test_accuracy=metrics.accuracy_score(Y_test,Y_test_pred)\n",
    "print(\"训练集准确率:\",train_accuracy)\n",
    "print(\"测试集准确率:\",test_accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'实验四数据集网格搜索决策树.pdf'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dot_data = export_graphviz(model, out_file=None,feature_names=['Wet','Dry','Ele','Slope','Aspect'],class_names=['F','T'],filled=True) \n",
    "graph = graphviz.Source(dot_data)\n",
    "graph.render('实验四数据集网格搜索决策树')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过设置权重平衡两类参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy 0.9583333333333334\n",
      "混淆矩阵\n",
      " [[99  3]\n",
      " [ 2 16]]\n",
      "f1score 0.9587937691385966\n"
     ]
    }
   ],
   "source": [
    "# 手动设置类别影响权重平衡决策树\n",
    "clf_balanced = DecisionTreeClassifier(class_weight=\"balanced\", random_state=0)\n",
    "clf_balanced.fit(X_train, Y_train)\n",
    "\n",
    "# 进行预测并计算准确率\n",
    "Y_pred_balanced = clf_balanced.predict(X_test)\n",
    "accuracy = metrics.accuracy_score(Y_test, Y_pred_balanced)\n",
    "confusion_matrix = metrics.confusion_matrix(Y_test, Y_pred_balanced)\n",
    "f1score = metrics.f1_score(Y_test, Y_pred_balanced, average='weighted')\n",
    "print('accuracy', accuracy)\n",
    "print('混淆矩阵\\n', confusion_matrix)\n",
    "print('f1score', f1score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'实验四数据集平衡权重决策树.pdf'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dot_data = export_graphviz(clf_balanced, out_file=None,feature_names=['Wet','Dry','Ele','Slope','Aspect'],class_names=['F','T'],filled=True) \n",
    "graph = graphviz.Source(dot_data)\n",
    "graph.render('实验四数据集平衡权重决策树')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用网格搜索进一步提高准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最优参数: {'criterion': 'gini', 'max_depth': 9, 'max_features': 'sqrt', 'min_samples_leaf': 1, 'min_samples_split': 3}\n",
      "训练集准确率: 0.9916666666666667\n",
      "测试集准确率: 0.9416666666666667\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\model_selection\\_validation.py:425: FitFailedWarning: \n",
      "3024 fits failed out of a total of 9072.\n",
      "The score on these train-test partitions for these parameters will be set to nan.\n",
      "If these failures are not expected, you can try to debug them by setting error_score='raise'.\n",
      "\n",
      "Below are more details about the failures:\n",
      "--------------------------------------------------------------------------------\n",
      "1760 fits failed with the following error:\n",
      "Traceback (most recent call last):\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\model_selection\\_validation.py\", line 732, in _fit_and_score\n",
      "    estimator.fit(X_train, y_train, **fit_params)\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\base.py\", line 1144, in wrapper\n",
      "    estimator._validate_params()\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\base.py\", line 637, in _validate_params\n",
      "    validate_parameter_constraints(\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\utils\\_param_validation.py\", line 95, in validate_parameter_constraints\n",
      "    raise InvalidParameterError(\n",
      "sklearn.utils._param_validation.InvalidParameterError: The 'max_features' parameter of DecisionTreeClassifier must be an int in the range [1, inf), a float in the range (0.0, 1.0], a str among {'log2', 'sqrt'} or None. Got 'auto' instead.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "1264 fits failed with the following error:\n",
      "Traceback (most recent call last):\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\model_selection\\_validation.py\", line 732, in _fit_and_score\n",
      "    estimator.fit(X_train, y_train, **fit_params)\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\base.py\", line 1144, in wrapper\n",
      "    estimator._validate_params()\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\base.py\", line 637, in _validate_params\n",
      "    validate_parameter_constraints(\n",
      "  File \"c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\utils\\_param_validation.py\", line 95, in validate_parameter_constraints\n",
      "    raise InvalidParameterError(\n",
      "sklearn.utils._param_validation.InvalidParameterError: The 'max_features' parameter of DecisionTreeClassifier must be an int in the range [1, inf), a float in the range (0.0, 1.0], a str among {'sqrt', 'log2'} or None. Got 'auto' instead.\n",
      "\n",
      "  warnings.warn(some_fits_failed_message, FitFailedWarning)\n",
      "c:\\ProgramData\\anaconda3\\envs\\myenv2\\lib\\site-packages\\sklearn\\model_selection\\_search.py:976: UserWarning: One or more of the test scores are non-finite: [       nan        nan        nan ... 0.86041667 0.86041667 0.86041667]\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "param_grid={'max_depth':np.arange(3,10,1),'min_samples_split':np.arange(2,10,1),\n",
    "            'criterion':['gini','entropy'],'min_samples_leaf':np.arange(1,10,1),'max_features':['auto','sqrt','log2']}\n",
    "clf3=DecisionTreeClassifier(random_state=0,class_weight=\"balanced\")\n",
    "grid_search=GridSearchCV(clf3,param_grid,cv=3,n_jobs=-1)\n",
    "grid_search.fit(X_train,Y_train)\n",
    "print(\"最优参数:\",grid_search.best_params_)\n",
    "\n",
    "#使用最优参数重新训练模型\n",
    "best_tree=grid_search.best_estimator_\n",
    "model=best_tree.fit(X_train,Y_train)\n",
    "Y_train_pred=model.predict(X_train)\n",
    "Y_test_pred=model.predict(X_test)\n",
    "train_accuracy=metrics.accuracy_score(Y_train,Y_train_pred)\n",
    "test_accuracy=metrics.accuracy_score(Y_test,Y_test_pred)\n",
    "print(\"训练集准确率:\",train_accuracy)\n",
    "print(\"测试集准确率:\",test_accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'实验四数据集平衡权重网格搜索决策树.pdf'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dot_data = export_graphviz(model, out_file=None,feature_names=['Wet','Dry','Ele','Slope','Aspect'],class_names=['F','T'],filled=True) \n",
    "graph = graphviz.Source(dot_data)\n",
    "graph.render('实验四数据集平衡权重网格搜索决策树')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "myenv2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
